package com.smedi.ismedi.progress.core.port.adapter.persistence.repository.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.smedi.ismedi.authority.starter.util.AuthorityUtil;
import com.smedi.ismedi.progress.api.dto.request.VersionManageCreateRequest;
import com.smedi.ismedi.progress.core.application.command.*;
import com.smedi.ismedi.progress.core.application.service.ProgressApplicationService;
import com.smedi.ismedi.progress.core.domain.aggregatemodel.ProcessTask;
import com.smedi.ismedi.progress.core.domain.aggregatemodel.Progress;
import com.smedi.ismedi.progress.core.domain.repository.ProjectVersionRepository;
import com.smedi.ismedi.progress.core.infrastructure.constant.ConstantField;
import com.smedi.ismedi.progress.core.infrastructure.util.mpp.MppTask;
import com.smedi.ismedi.progress.core.infrastructure.util.mpp.MppUtil;
import com.smedi.ismedi.progress.core.port.adapter.convert.AdapterConverter;
import com.smedi.ismedi.progress.core.port.adapter.persistence.model.VersionDetailEntity;
import com.smedi.ismedi.progress.core.port.adapter.persistence.model.VersionManageEntity;
import com.smedi.ismedi.progress.core.port.adapter.persistence.mybatis.mapper.VersionManageMapper;
import com.smedi.ismedi.progress.core.port.adapter.service.ProcessRemoteService;
import com.smedi.ismedi.progress.core.port.adapter.service.TaskRemoteService;
import com.smedi.ismedi.web.starter.exception.ErrorItem;
import com.smedi.ismedi.web.starter.exception.LogicException;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;

import static com.smedi.ismedi.progress.core.infrastructure.constant.ConstantField.*;
import static java.time.format.DateTimeFormatter.ISO_DATE;

/**
 * @author hexu@goldbeacon.cn
 * @version 1.0
 * @remark ...
 * @date 2022/10/11 15:13
 */
@Repository
@AllArgsConstructor
@Slf4j
public class ProjectVersionRepositoryImpl implements ProjectVersionRepository {
    private final AdapterConverter adapterConverter;
    private final AuthorityUtil authorityUtil;
    private final VersionManageMapper versionManageMapper;
    private final ProgressApplicationService progressApplicationService;
    private static final String PROJECT_TEMPLATE_FILE = "模板-进度计划.mpp";


    private final ProcessRemoteService processRemoteService;


    private final TaskRemoteService taskRemoteService;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void versionImport(MultipartFile projectFile, VersionManageCreateRequest versionManageCreateRequest) {
        // 新增之前，首先判断是否有历史版本正在审批，如果有这件审批中的任务退回，且将发生的待办通知修改为已处理
       List<Long> list = versionManageMapper.selectProjecApproveStatus(versionManageCreateRequest.getProjectId());
       if(list!=null && !list.isEmpty()){
           for (Long v: list) {
               // 处理通知
               taskRemoteService.editTask(TaskRecordEditCommand.builder()
                       .sourceFromId(v)
                       .taskType(ConstantField.TASK_TYPE)
                       .taskName(ConstantField.TASK_NAME_PROGRESS_CONSTRUCTION_APPROVAL)
                       .taskStatus("进行中")
                       .oldStatus(new ArrayList<>(Collections.singletonList("已完成")))
                       .finishTime(LocalDateTime.now())
                       .build());
               // 退回任务
               Map<String, Object> variables = new HashMap<>();
               variables.put(METHOD, "NOT_PASS");
               try {
                   ProcessTask prcessTask = processRemoteService.completeProcessTask(ProcessTaskCompleteCommand.builder()
                           .businessCode(String.valueOf(v))
                           .businessType(CRANE)
                           .processDefinitionKey(PROCESS_VERSION)
                           .comment("系统处理")
                           .variables(variables)
                           .build());
                   // 更新任务状态
                   versionManageMapper.updateApproveStatus(v,prcessTask.getStatus());
               }catch (LogicException logicException){
                    // 任务可能已经完成，则会抛出改一异常
                   log.info("businessCode:{},当前流程已经结束",v);
               }
           }

       }


        InputStream inputStream = null;
        try {
            inputStream = projectFile.getInputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //获取mpp文件信息
        StringBuilder verificationPeerNameError = new StringBuilder();
        List<MppTask> mppTasks = MppUtil.getTaskData(inputStream, verificationPeerNameError);
        //校验必填项
        if (CollectionUtils.isEmpty(mppTasks)) {
            throw LogicException.raise(new ErrorItem(25, "文件内容不能为空！"));
        }
        String errorInfo = MppUtil.verificationTaskRequiredField(mppTasks);
        if (verificationPeerNameError.length() != 0) {
            errorInfo = (StringUtils.isNotBlank(errorInfo) ? (errorInfo + "\n") : "" )  + "同级下存在同任务名" + verificationPeerNameError.toString() + "!";
        }
        if (StringUtils.isNotBlank(errorInfo)) {
            throw LogicException.raise(new ErrorItem(25, errorInfo));
        }
        List<MppTask> tempMppTasks = new ArrayList<>();
        mppTasks.forEach(task ->{
            MppTask mpp = new MppTask();
            mpp.setName(task.getName());
            mpp.setParentName(task.getParentName());
            tempMppTasks.add(mpp);
        });
        Set<MppTask> duplicates = new HashSet<>();
        for (MppTask item : tempMppTasks) {
            if (!duplicates.add(item)) {
                throw LogicException.raise(new ErrorItem(25, "存在“任务名称+子级任务名称”相同的情况。如【"+item.getParentName()+"】与子级任务【"+item.getName()+"】，请修改后再上传"));
            }
        }
        //保存版本信息
        VersionManageEntity versionManageEntity = adapterConverter.versionManageCreateRequestToVersionManageEntity(versionManageCreateRequest);
        LocalDateTime localDateTime = LocalDateTime.now();
        versionManageEntity.setLatestUpdatedDate(localDateTime);
        versionManageEntity.setCreatedDate(localDateTime);
        versionManageEntity.setCreatedUserId(authorityUtil.getPersonId());
        versionManageEntity.setLatestUpdatedUserId(authorityUtil.getPersonId());
        versionManageEntity.setProjectId(versionManageCreateRequest.getProjectId());
        versionManageEntity.setScheduleName(versionManageCreateRequest.getScheduleName());
        versionManageEntity.setCompilePerson(versionManageCreateRequest.getCompilePerson());
        versionManageEntity.setStatus(0L);
        if(StringUtils.isNotBlank(versionManageCreateRequest.getCompileDate())) {
            LocalDate compileDate = LocalDate.parse(versionManageCreateRequest.getCompileDate(), ISO_DATE);
            versionManageEntity.setSubmitTime(LocalDateTime.now());
        }
        versionManageEntity.setDescription(versionManageCreateRequest.getDescription());
        //查询当前最大版本号
        Integer maxVersion = versionManageMapper.queryCurrentProjectMaxVersion(versionManageEntity.getProjectId());
        if (maxVersion == null) { maxVersion = 0; }
        maxVersion = maxVersion + 1;
        versionManageEntity.setVersion(maxVersion);
        versionManageMapper.insertVersionManage(versionManageEntity);
        //更新版本号
        versionManageMapper.updateProjectVersion(versionManageEntity.getProjectId(), maxVersion, versionManageEntity.getId());

        //查询当前最大ID
        Integer maxId = versionManageMapper.queryVersionDetailMaxId();
        if (maxId == null) { maxId = 1; }
        List<VersionDetailEntity> versionDetailEntities = new ArrayList<>();
        //关联关系(key:旧ID，val:新ID)
        LinkedHashMap<Long, Long> linkMap = new LinkedHashMap<>();
        for(MppTask mppTask: mppTasks) {
            mppTask.setNewId(Long.valueOf(++maxId));
            linkMap.put(mppTask.getId(), mppTask.getNewId());
        }
        //重建关联关系
        for(MppTask mppTask: mppTasks) {
            if (mppTask.getParentId() != 0 && mppTask.getParentId() != null) {
                Long oldParentId = mppTask.getParentId();
                mppTask.setParentId(linkMap.get(oldParentId));
            }
        }

        for(MppTask mppTask: mppTasks) {
            VersionDetailEntity versionDetailEntity = new VersionDetailEntity();
            versionDetailEntity.setId(mppTask.getNewId());
            versionDetailEntity.setParentId(mppTask.getParentId());
            versionDetailEntity.setParentName(mppTask.getParentName());
            versionDetailEntity.setVersionManageId(versionManageEntity.getId());
            versionDetailEntity.setNamePrefix(mppTask.getNamePrefix());
            versionDetailEntity.setName(mppTask.getName());
            versionDetailEntity.setVersion(maxVersion);
            versionDetailEntity.setSortIndex(mppTask.getNumbers());
            versionDetailEntity.setProjectId(versionManageCreateRequest.getProjectId());

            List<String> types = new ArrayList<>();
            //里程碑任务
            if (Boolean.TRUE.equals(mppTask.getMilestone())) {
                types.add("0");
            }
            //关键任务
            if (Boolean.TRUE.equals(mppTask.getCritical())) {
                types.add("1");
            }
            switch (mppTask.getTaskLevel()) {
                //一级任务
                case 2: types.add("4"); break;
                //二级任务
                case 3: types.add("5"); break;
                //三级任务
                case 4: types.add("6"); break;
                //四级任务
                case 5: types.add("7"); break;
                //五级任务
                case 6: types.add("8"); break;
                default: break;
            }
            if (CollectionUtils.isEmpty(types)) {
                //设为其他任务
                types.add("3");
            }
            versionDetailEntity.setType(String.join(",", types));
            versionDetailEntity.setScheduleStartTime(mppTask.getStartDate());
            versionDetailEntity.setScheduleEndTime(mppTask.getEndDate());
            versionDetailEntity.setSchduleDuration(Long.valueOf(mppTask.getDuration()));
            versionDetailEntity.setLatestUpdatedDate(localDateTime);
            versionDetailEntity.setCreatedDate(localDateTime);
            versionDetailEntity.setPercentage("0");
            versionDetailEntity.setCreatedUserId(authorityUtil.getPersonId());
            versionDetailEntity.setLatestUpdatedUserId(authorityUtil.getPersonId());
            versionDetailEntity.setResponsiblePerson(mppTask.getResourceName());
            versionDetailEntities.add(versionDetailEntity);
        }
        versionManageMapper.batchInsertVersionDetail(versionDetailEntities);

        //更新版本号
        versionManageMapper.updateVersionDetailVersion(versionManageEntity.getProjectId(), maxVersion, versionManageEntity.getId());

        Progress progress = new Progress();
        progress.setProjectId(versionManageCreateRequest.getProjectId());
        progress.setId(versionManageEntity.getId());
        progress.setName(versionManageCreateRequest.getScheduleName());
        progress.setCompilePerson(versionManageCreateRequest.getCompilePerson());
        progressApplicationService.progressWorkorder(progress);
    }

    @Override
    public ResponseEntity<byte[]> downloadProjectTemplateFile() {
        try {
            Resource resource = new ClassPathResource("fileTemplate/" + PROJECT_TEMPLATE_FILE);
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
            headers.setContentDispositionFormData("attachment", new String(PROJECT_TEMPLATE_FILE.getBytes(), StandardCharsets.ISO_8859_1));
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            InputStream inputStream = resource.getInputStream();
            int len;
            byte[] buffer = new byte[1024];
            while ((len = inputStream.read(buffer)) > 0) {
                byteArrayOutputStream.write(buffer, 0, len);
            }
            inputStream.close();
            return new ResponseEntity<>(byteArrayOutputStream.toByteArray(), headers, HttpStatus.OK);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }

    }

    @Override
    public String cancelVersion(ProgressViewCommand progressViewCommand) {
        try{
            LambdaQueryWrapper<VersionManageEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(ObjectUtils.isNotNull(progressViewCommand.getProjectId()), VersionManageEntity::getProjectId, progressViewCommand.getProjectId());
            lambdaQueryWrapper.eq(ObjectUtils.isNotNull(progressViewCommand.getId()), VersionManageEntity::getId, progressViewCommand.getId());
            lambdaQueryWrapper.eq(VersionManageEntity ::getMainCourtyardApproval,1);
            VersionManageEntity progressEntity = versionManageMapper.selectOne(lambdaQueryWrapper);
            if(progressEntity == null){
                return "0";//审批状态不为待审批，不能撤销
            }else{
                Progress progress = new Progress();
                progress.setProjectId(progressEntity.getProjectId());
                progress.setId(progressEntity.getId());
                progressApplicationService.cancelPojectProgress(progress);
                progressEntity.setMainCourtyardApproval(5l);//已撤销
                versionManageMapper.updateById(progressEntity);
                return "1";
            }
        }catch (Exception e){
            e.printStackTrace();
            return "2";
        }
    }

    /**
     * 转换为文件名
     *
     * @param request 请求
     * @param fileName 文件名称
     * @return 文件名
     * @throws UnsupportedEncodingException 编码异常
     */
    private static String convertToFileName(HttpServletRequest request, String fileName) throws UnsupportedEncodingException {
        // 针对IE或者以IE为内核的浏览器：
        String userAgent = request.getHeader("User-Agent");
        if (userAgent.contains("MSIE") || userAgent.contains("Trident")) {
            fileName = URLEncoder.encode(fileName, "UTF-8");
        } else {
            // 非IE浏览器的处理：  
            fileName = new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
        }
        return fileName;
    }
}
